home *** CD-ROM | disk | FTP | other *** search
/ The Programmer Disk / The Programmer Disk (Microforum).iso / xpro / c3 / pro24 / mpu.c < prev    next >
C/C++ Source or Header  |  1986-08-07  |  34KB  |  1,147 lines

  1. /*****************************************************************************
  2. *        Change Log
  3. *  Date        | Change
  4. *-----------+-----------------------------------------------------------------
  5. * 31-Dec-85 | Created changelog
  6. * 31-Dec-85 | Add c:\ to include directives
  7. * 31-Dec-85 | Call setctl/clrctl to deal with ctrl-break intercept.  Note that
  8. *        | clrctl can be called several times, as might be the case during
  9. *        | a ctrl-break abort
  10. *  1-Jan-86 | <rgd/jmn> Added keyloud
  11. *        | Added initialized flag
  12. * 21-Jan-86 | Abort l_restuntil if Ctrl-C or Ctrl-Break is typed
  13. * 21-Jan-86 | Took out mpu_unknown, replaced with mpu_error_check
  14. *  3-Feb-86 | Fixed MIDI_PROGRAM and MIDI_CHANNEL to subtract one to account
  15. *        | for MIDI encodings, e.g. channel 1 is represented by 0
  16. *  8-Feb-86 | Added midi_exclusive to turn on/off flag in mpu-401.
  17. *        | Added midi_buffer function.
  18. * 18-Feb-86 | Changed midi_exclusive to exclusive.
  19. *        | Added midi_exclusive to send an exclusive message.
  20. * 19-Feb-86 | Changed MC_SEND_... to MC_SND_... to avoid name clash
  21. * 23-Feb-86 | Added midi_control, midi_bend, midi_touch routines
  22. * 24-Feb-86 | Added call to init_asm from musicinit.
  23. * 26-Mar-86 | Added midi_cont call to enable continuous control messages
  24. * 18-Apr-86 | Cleaned up documentation, renamed midi_control to midi_ctrl
  25. *  2-Jun-86 | Added tuning definition code.
  26. * 30-Jun-86 | Added switch to use timdif.asm instead of MPU-401 for timing
  27. * 18-Jul-86 | Added DEBUG switch in parallel with DEBUG in AINTR.ASM
  28. * 29-Jul-86 | Changed trace flag checking to first initialization only.
  29. *  5-Aug-86 | Minor changes for Lattice C Version 3.00
  30. *****************************************************************************/
  31.  
  32. /*
  33.  * Driver for MPU-401
  34.  *
  35.  * This module initializes things and then issues commands to the
  36.  * MPU-401 in response to higher-level operations like note( , , ).
  37.  * Unlike examples in the MPU-401 manual, these routines do not wait
  38.  * for Acks by polling the MPU-401.  Instead, Acks and all other
  39.  * input are handled by the interrupt routine (see aintr.asm), which
  40.  * sets a flag whenever it sees an Ack.     Therefore, these routines
  41.  * just poll the Ack flag rather than directly reading the MPU-401.
  42.  * This avoids the problem of the MPU-401 having data queued in front
  43.  * of the Ack message.
  44.  */
  45.  
  46. /*
  47.  * Interface Specifications for aintr.asm to mpu.c:
  48.  *
  49.  * aintr.asm is an interrupt handler that also parses midi data and
  50.  * queues it for receipt by mpu.c.  In this way, interrupts are hidden
  51.  * from C programmers and yet the mpu-401 never hangs trying to deliver
  52.  * data because the interrupt routine is always ready to read data.
  53.  * 
  54.  * Data is parsed by aintr.asm in order to know how much data to read.
  55.  * To avoid reparsing at the C level, the data is buffered in a
  56.  * queue of messages rather than a simple byte stream.    Each message
  57.  * is a 4-byte block.  The first byte is a status byte and the following
  58.  * bytes (one or two) are data bytes.
  59.  * 
  60.  * Note that timing is not specified.  Later, we may add a parallel
  61.  * buffer to store 4-byte timing blocks if it seems necessary.
  62.  * 
  63.  * System exclusive messages are handled by copying the midi exclusive
  64.  * data into a separate buffer provided by the application program
  65.  * through the midi_buffer call.
  66.  * 
  67.  */
  68.  
  69. /* define DEBUG to enable some extra debugging */
  70. /* #define DEBUG 1 */
  71.  
  72.  
  73. /* define TIMDIF to use the timdif.asm module */
  74. /* #define TIMDIF 1 */
  75.  
  76. #include "cext.h"
  77. #include "stdio.h"
  78. #include "atxt.h"
  79. #include "mpu.h"
  80. #include "midicode.h"
  81. #include "cmdline.h"
  82. #include "userio.h"
  83. #include "pitch.h"
  84. #include "cintr.h"
  85.  
  86. #ifdef TIMDIF
  87. #include "timdif.h"
  88. #endif
  89.  
  90. #define BREAKTEST    if (CBREAK) {    /* Ctrl-C or Ctrl-Break handler */ \
  91.         printf("Exiting.\n");\
  92.         musicterm();\
  93.         exit(1);\
  94.     }
  95. #define num_voices 16
  96.  
  97. /****************************************************************************
  98. *
  99. * MPU 401 commands
  100. *
  101. ****************************************************************************/
  102.  
  103. #define MC_RESET        0xff
  104. #define MC_SET_TEMPO        0xe0
  105. #define MC_TIMEBASE_192        0xc8
  106. #define MC_START_RECORDING    0x22
  107. #define MC_RECORD_COUNTER    0xab
  108. #define MC_ON_METRONOME        0x85
  109. #define MC_VERSION        0xac
  110. #define MC_REVISION        0xad
  111. #define MC_NO_MEASURE_END    0x8c
  112. #define MC_SND_MIDI        0xd0
  113. #define MC_SND_EXCLUSIVE    0xdf
  114. #define MC_EXCLUSIVE        0x96
  115. #define MC_OFF_BEND        0x86
  116. #define MC_ON_BEND        0x87
  117. #define MC_OFF_THRU        0x88
  118. #define MC_ON_THRU        0x89
  119.  
  120. /****************************************************************************
  121. *
  122. * useful defines and macros
  123. *
  124. ****************************************************************************/
  125.  
  126. #define MD_BEATS_PER_MINUTE    125    /* to get 400 ticks per sec */
  127. #define TICKS_TO_HUNDREDTHS(t)    ((t) >> 2)
  128. #define HUNDREDTHS_TO_TICKS(h)    ((h) << 2)
  129. #define NONE            (-1)
  130.  
  131. /****************************************************************************
  132. *
  133. * MPU-401 interface to IBM-XT
  134. *
  135. ****************************************************************************/
  136.  
  137. #define DATAPORT    0x330        /* Input data port of MPU 401 */
  138. #define STATPORT    0x331        /* status and request port */
  139. #define COMPORT        0x331        /* Send MPU 401 commands to here */
  140. #define DSR        (1<<7)        /* This bit of STATPORT, when low,
  141.                        means the 401 has Data to send */
  142. #define DRR        (1<<6)        /* This bit of STATPORT, when low,
  143.                        means the 401 will take commands */
  144. #define ACK        0xfe        /* Acknowledgement data code */
  145. #define IRQ        2        /* Interrupt request line of 401 */
  146. #define MAX_ACK_WAIT 1000
  147.  
  148. /****************************************************************************
  149. *
  150. * exported flags
  151. *
  152. ****************************************************************************/
  153.  
  154. boolean musictrace = false;    /* enables printed trace of commands */
  155. boolean miditrace = false;    /* enables printed trace of MIDI output */
  156.  
  157. #define n_t_sw 2
  158. private char *t_switches[n_t_sw] = { "-t", "-trace" };
  159.  
  160. #define n_m_sw 2
  161. private char *m_switches[n_m_sw] = { "-m", "-miditrace" };
  162.  
  163. /****************************************************************************
  164. *
  165. * exported variables
  166. *
  167. ****************************************************************************/
  168.  
  169. int keyloud;    /* set to velocity of last getkey event */
  170.  
  171.  
  172. /****************************************************************************
  173. *
  174. * variables shared with aintr.asm
  175. *
  176. ****************************************************************************/
  177.  
  178. int    intnest = 0;    /* do not touch...read-only except by aintr.asm */
  179. int    rd_delay = 0;    /* do not touch...read-only except by aintr.asm */
  180.  
  181. int    Unknown = ACK;
  182. int    interror = 0;    /* reports errors from interrupt handler */
  183. int    timeerr = 0;    /* reports timeout errors */
  184.  
  185. #ifdef DEBUG
  186. int    intcnt = 0;    /* Count of interrupts taken */
  187. int    loop_cnt, loop_max;    /* iteration counts */
  188. #endif
  189.  
  190. long    Ticks;        /* Number of clock ticks since init */
  191. int    Ack;        /* True if command has been acknowledged */
  192. char    MidiTime, MidiStat = 0x90, Midi1, Midi2, Midi3; /* midi and time */
  193. char    exclflag = 0;    /* used by aintr,  DO NOT TOUCH */
  194. int    time_req = 0;    /* set to 1 when Ack will be followed by data */
  195. int    mpu_result;    /* the data following the Ack */
  196.  
  197.  
  198. /****************************************************************************
  199. *
  200. * Variable set by BREAK module
  201. *
  202. ****************************************************************************/
  203.  
  204. extern int CBREAK;
  205.  
  206.  
  207. /****************************************************************************
  208. *
  209. * variable imported from cintr.c
  210. *
  211. ****************************************************************************/
  212.  
  213. extern int enabled;
  214.  
  215.  
  216. /****************************************************************************
  217. *
  218. * local module variables
  219. *
  220. ****************************************************************************/
  221.  
  222. private int initialized = false;  /* set by musicinit, cleared by musicterm */
  223. private boolean tune_flag = false; /* set by musicinit, never cleared */
  224. private boolean metroflag = false; /* flag to turn on metronome */
  225. private boolean mpuflag = true;    /* true iff mpu401 present */
  226. private int len;        /* length of trace string */
  227. private int last_cmd = 0;    /* last mpu_command, used by trace */
  228. private int user_scale = false; /* true if user-defined scale */
  229. private int bend[num_voices];    /* current pitch bend on channel */
  230. private pitch_table pit_tab[128];    /* scale definition */
  231.  
  232. /* "temporary" instrumentation: how long should we wait? */
  233. private int max_ack_wait = 0;        /* maintained by mpu_wait */
  234.  
  235. /****************************************************************************
  236. *
  237. * functions declared in this module
  238. *
  239. ****************************************************************************/
  240.  
  241. private void    fixup();
  242. private void    mpu_command();
  243. private void    mpu_drr_wait();
  244. private int    mpu_read();
  245. private void    mpu_wait();
  246. private void    mpu_write();
  247. private void    trace_mpu_command();
  248. private void    wfa();
  249.  
  250.  
  251. /****************************************************************************
  252. *
  253. * Buffer 
  254. *    shares data with aintr.asm (the producer)
  255. *
  256. ****************************************************************************/
  257.  
  258. #define BUFFERSIZE 1024
  259. byte    buff[BUFFERSIZE];    /* data buffer */
  260. int    buffhead = 0;        /* buffer pointers */
  261. int    bufftail = 0;
  262.  
  263.  
  264. /****************************************************************************
  265. *
  266. * System exclusive buffer variables (shared with aintr.asm)
  267. *
  268. ****************************************************************************/
  269.  
  270. byte *xbuff = 0;    /* address of the user-supplied buffer */
  271. int xbuffmask;        /* mask for circular buffer address calculation */
  272. int xbuffhead = 0;    /* buffer pointers */
  273. int xbufftail = 0;
  274.  
  275. /****************************************************************************
  276. *                 exclusive
  277. * Inputs:
  278. *    boolean onflag -- set to true to receive midi exclusive data
  279. * Effect: 
  280. *    Tells MPU401 to read exclusive messages into buffer
  281. ****************************************************************************/
  282.  
  283. void exclusive(onflag)
  284.     boolean onflag; /* on or off? */
  285. {
  286.     if  (!initialized) fixup();
  287.     if (musictrace)
  288.         printf("exclusive: %d\n", onflag);
  289.     mpu_command(MC_EXCLUSIVE | (onflag ? 1 : 0));
  290. }
  291.  
  292. /****************************************************************************
  293. *                     fixup
  294. * Effect: 
  295. *    Print error message and call musicinit
  296. ****************************************************************************/
  297.  
  298. private void fixup()
  299. {
  300.     printf("You forgot to call musicinit.  I'll do it for you.\n");
  301.     musicinit();
  302. }
  303.  
  304. /****************************************************************************
  305. *                    getbuf
  306. * Inputs:
  307. *    boolean waitflag: true if routine should wait for data
  308. *    byte * p: Pointer to data destination
  309. * Result: boolean
  310. *    true if data was written to *p
  311. *    false if data not written to *p
  312. * Effect: 
  313. *    copies data from buffer to *p
  314. *    will wait for buffer to become nonempty if waitflag is true
  315. ****************************************************************************/
  316.  
  317. boolean getbuf(waitflag, p)
  318.    boolean waitflag;    /* true if routine should wait for data */
  319.    byte *p;    /* pointer to data destination */
  320. {
  321. /*    register int head;*/
  322.  
  323.     if (!initialized) fixup();
  324.     if (waitflag) while (buffhead == bufftail) /* wait */ ;
  325.     else if (buffhead == bufftail) return false;
  326.  
  327.     *(long *)p = *(long *)(buff+buffhead);
  328.     buffhead += 4;
  329.     if (buffhead >= BUFFERSIZE) buffhead = 0;
  330.  
  331. /* the previous three lines are an optimization of:
  332.  *    head = buffhead;
  333.  *    *p++ = buff[head++];
  334.  *    *p++ = buff[head++];
  335.  *    *p++ = buff[head++];
  336.  *    head++;
  337.  *
  338.  *    if (head >= BUFFERSIZE) head = 0;
  339.  *    buffhead = head;
  340.  */
  341.     return true;
  342. }
  343.  
  344. /****************************************************************************
  345. *                    getkey
  346. * Inputs:
  347. *    boolean waitflag: true if wait until key depression, false if
  348. *              return immediately
  349. * Result: int
  350. *    key number of key which has been depressed
  351. *    It returns -1 if waitflag is false and no key has been pressed
  352. *    If waitflag is true this routine will block until a key is pressed
  353. * Effect: 
  354. *    reads a key
  355. ****************************************************************************/
  356.  
  357. int getkey(waitflag)
  358. {
  359.     byte msg[4];
  360.     int k;
  361.  
  362.     if (!initialized) fixup();
  363.     while (true) {    /* process data until you find a note */
  364.     /* look for data and exit if none found */
  365.     /* NOTE: waitflag will force waiting until data arrives */
  366.     if (!getbuf(waitflag, msg)) { /* nothing there */
  367.         k = -1;
  368.         break;
  369.     } else if ((msg[0] & MIDI_CODE_MASK) == MIDI_ON_NOTE) {
  370.         if (msg[2] == 0) { /* velocity 0 -> note off */
  371.         keyloud = 0;
  372.         k = (msg[1]-12) + 128;
  373.         } else {
  374.         keyloud = msg[2];
  375.         k = (msg[1]-12);
  376.         }
  377.         break;
  378.     } else if ((msg[0] & MIDI_CODE_MASK) == MIDI_OFF_NOTE) {
  379.         keyloud = 0;
  380.         k = (msg[1]-12) + 128;
  381.         break;
  382.     }
  383.     }
  384.     if (musictrace) {
  385.     if (k != -1) printf("getkey got %d\n", k);
  386.     }
  387.     return k;
  388. }
  389.  
  390. /****************************************************************************
  391. *                    gettime
  392. * Result: long
  393. *    current timestamp from MPU-401
  394. *     Return the time in 100ths of seconds since the last call to
  395. *     musicinit or timereset
  396. * Effect: 
  397. *    Reads the MPU-401 time
  398. ****************************************************************************/
  399.  
  400. /* just to make sure we're using the timdif module: */
  401. long gettime()
  402. {
  403.     BREAKTEST    /* abort if user typed Ctrl Break */
  404.  
  405.     if    (!initialized) fixup();
  406. #ifndef TIMDIF
  407.     time_req = 1;    /* tell aintr.asm to read extra byte */
  408.     mpu_command(MC_RECORD_COUNTER);        /* Read counter */
  409.     return TICKS_TO_HUNDREDTHS(Ticks);
  410. #else
  411.     return ibm_time();
  412. #endif
  413. }
  414.  
  415. /****************************************************************************
  416. *                    l_rest
  417. * Inputs:
  418. *    long time: Amount of time to rest
  419. * Effect: 
  420. *    Waits until the amount of time specified has lapsed
  421. ****************************************************************************/
  422.  
  423. void l_rest(time)
  424.     long time;
  425. {
  426.     if (!initialized) fixup();
  427.     l_restuntil(time + gettime());    
  428. }
  429.  
  430. /****************************************************************************
  431. *                  l_restuntil
  432. * Inputs:
  433. *    long time: Event time to rest until
  434. * Effect: 
  435. *    Waits until the specified time has been reached (absolute time)
  436. ****************************************************************************/
  437.  
  438. void l_restuntil(time)
  439.     long time;
  440. {
  441.     while(time > gettime()) ;
  442. }
  443.  
  444. /****************************************************************************
  445. *                metronome
  446. * Inputs:
  447. *    int onflag: true or false
  448. * Effect:
  449. *    enables (true) or disables (false) MPU-401 metronome function.
  450. *    must be called before musicinit
  451. ****************************************************************************/
  452.  
  453. void metronome(onflag)
  454.     int onflag;
  455. {
  456.     metroflag = onflag;
  457. }
  458.  
  459. /****************************************************************************
  460. *                   midi_bend
  461. * Inputs:
  462. *    int channel: midi channel on which to send data
  463. *    int value: pitch bend value
  464. * Effect: 
  465. *    Sends a midi pitch bend message
  466. ****************************************************************************/
  467.  
  468. void midi_bend(channel, value)
  469.     int channel, value;
  470. {
  471.     if    (!initialized) fixup();
  472.     if (musictrace)
  473.     printf("midi_bend: ch %d, val %d\n", channel, value);
  474.     bend[MIDI_CHANNEL(channel)] = value;
  475.     mpu_command(MC_SND_MIDI);
  476.     mpu_write(MIDI_BEND | MIDI_CHANNEL(channel));
  477.     mpu_write(MIDI_DATA(value));
  478.     mpu_write(MIDI_DATA(value>>7));
  479. }
  480.  
  481. /****************************************************************************
  482. *                midi_buffer
  483. * Inputs:
  484. *    byte * buffer: the buffer address
  485. *    int size: number of bytes in buffer
  486. * Returns:
  487. *    false if size is less than 16 or buffer is NULL, otherwise true
  488. * Effect:
  489. *    tells interrupt routine to store system exclusive messages in
  490. *    buffer.     The largest power of 2 bytes less than size will be
  491. *    used.  xbuffhead and xbufftail will be initialized to zero,
  492. *    and xbufftail will be one greater than the index of the last
  493. *    system exclusive byte read from mpu401.
  494. ****************************************************************************/
  495.  
  496. int midi_buffer(buffer, size)
  497.     byte *buffer;
  498.     int size;
  499. {
  500.     int mask;
  501.     mask = 16 - 1;
  502.     if (size < 16 || buffer == NULL) return false;
  503.     while (mask < size && mask > 0) mask = (mask << 1) + 1;
  504.     xbuff = NULL;    /* turn off buffering */
  505.     xbuffmask = mask >> 1;
  506.     xbuffhead = xbufftail = 0;
  507.     xbuff = buffer;    /* set buffer, turn on buffering */
  508.     return true;
  509. }
  510.  
  511. /****************************************************************************
  512. *                midi_cont
  513. * Inputs:
  514. *    boolean onflag: true or false
  515. * Effect:
  516. *    enables (true) or disables (false) continuous control info from
  517. *    MPU-401 to host.
  518. ****************************************************************************/
  519.  
  520. void midi_cont(onflag)
  521.     boolean onflag;
  522. {
  523.     if (onflag) mpu_command(MC_ON_BEND);
  524.     else mpu_command(MC_OFF_BEND);
  525. }
  526.  
  527. /****************************************************************************
  528. *                   midi_ctrl
  529. * Inputs:
  530. *    int channel: midi channel on which to send data
  531. *    int control: control number
  532. *    int value: control value
  533. * Effect: 
  534. *    Sends a midi control change message
  535. ****************************************************************************/
  536.  
  537. void midi_ctrl(channel, control, value)
  538.     int channel, control, value;
  539. {
  540.     if (!initialized) fixup();
  541.     if (musictrace)
  542.     printf("midi_ctrl: ch %d, ctrl %d, val %d\n", 
  543.         channel, control, value);
  544.     mpu_command(MC_SND_MIDI);
  545.     mpu_write(MIDI_CTRL | MIDI_CHANNEL(channel));
  546.     mpu_write(MIDI_DATA(control));
  547.     mpu_write(MIDI_DATA(value));
  548. }
  549.  
  550. /****************************************************************************
  551. *                 midi_exclusive
  552. * Inputs:
  553. *    byte * msg: pointer to a midi exclusive message, terminated by 0xF7
  554. * Effect: 
  555. *    Sends a midi exclusive message
  556. ****************************************************************************/
  557.  
  558. void midi_exclusive(msg)
  559.     byte *msg;    /* the data to be sent */
  560. {
  561.     int i;    /* can DX7 keep up? */
  562.  
  563.     /* if user mistakenly called midi_exclusive instead of exclusive,
  564.      * the argument will be true or false, both of which are highly    
  565.      * unlikely valid arguments for midi_exclusive:
  566.      */
  567.     if (msg == (byte *) false || msg == (byte *) true) {
  568.     printf("midi_exclusive: invalid argument %d.\n", (int) msg);
  569.     if (initialized) musicterm();
  570.     exit(1);
  571.     }
  572.  
  573.     if    (!initialized) fixup();
  574.     if (musictrace) printf("midi_exclusive\n");
  575.     mpu_command(MC_SND_EXCLUSIVE);
  576.     while (*msg != MIDI_EOX) {
  577.     mpu_write(*msg);
  578.     msg++;
  579.     /* This is a delay loop.  Without it, your DX7 will crash. */
  580.     for (i = (atxt() == ISAT ? 4 : 2); i > 0; i--) {
  581.         BREAKTEST
  582.     }
  583.     }
  584.     mpu_write(MIDI_EOX);
  585. }
  586.  
  587. /****************************************************************************
  588. *                   midi_note
  589. * Inputs:
  590. *    int channel: midi channel on which to send data
  591. *    int pitch: midi pitch code
  592. *    int velocity: velocity with which to sound it (0=> release)
  593. * Effect: 
  594. *    Sends a midi note-play request out
  595. ****************************************************************************/
  596.  
  597. void midi_note(channel, pitch, velocity)
  598.     int channel, pitch, velocity;
  599. {
  600.     if    (!initialized) fixup();
  601.     if (musictrace)
  602.     printf("midi_note: ch %d, key %d, vel %d\n",
  603.         channel, pitch, velocity);
  604.     if (user_scale) {
  605.     /* check for correct pitch bend */
  606.     if ((pit_tab[pitch+12].pbend != bend[MIDI_CHANNEL(channel)]) &&
  607.         (velocity != 0)) {
  608.         midi_bend(channel, pit_tab[pitch+12].pbend);
  609.         bend[channel] = pit_tab[pitch+12].pbend;
  610.     }
  611.     pitch = pit_tab[pitch+12].ppitch;
  612.     }
  613.     mpu_command(MC_SND_MIDI);
  614.     mpu_write(MIDI_ON_NOTE | MIDI_CHANNEL(channel));
  615.     mpu_write(MIDI_DATA(12 + pitch)); /* cmu standard to midi standard */
  616.     mpu_write(MIDI_DATA(velocity));
  617. }
  618.  
  619. /****************************************************************************
  620. *                 midi_program
  621. * Inputs:
  622. *    int channel: Channel on which to send midi program change request
  623. *    int program: Program number to send (decremented by 1 before
  624. *            being sent as midi data)
  625. * Effect: 
  626. *    Sends a program change request out the channel
  627. ****************************************************************************/
  628.  
  629. void midi_program(channel, program)
  630.     int channel;    /* midi channel */
  631.     int program;    /* the program number */
  632. {
  633.     if    (!initialized) fixup();
  634.     if (musictrace)
  635.     printf("midi_program: ch %d, prog %d\n",
  636.         channel, program);
  637.     mpu_command(MC_SND_MIDI);
  638.     mpu_write(MIDI_CH_PROGRAM | MIDI_CHANNEL(channel));
  639.     mpu_write(MIDI_PROGRAM(program));
  640. }
  641.  
  642. /****************************************************************************
  643. *                midi_thru
  644. * Inputs:
  645. *    boolean onflag: true or false
  646. * Effect:
  647. *    enables (true) or disables (false) midi thru info from
  648. *    MPU-401 to host.  (Default is set; reset with cmdline -block.)
  649. ****************************************************************************/
  650.  
  651. void midi_thru(onflag)
  652.     boolean onflag;
  653. {
  654.     if (onflag) mpu_command(MC_ON_THRU);
  655.     else mpu_command(MC_OFF_THRU);
  656. }
  657.  
  658. /****************************************************************************
  659. *                   midi_touch
  660. * Inputs:
  661. *    int channel: midi channel on which to send data
  662. *    int value: control value
  663. * Effect: 
  664. *    Sends a midi after touch message
  665. ****************************************************************************/
  666.  
  667. void midi_touch(channel, value)
  668.     int channel, value;
  669. {
  670.     if    (!initialized) fixup();
  671.     if (musictrace)
  672.     printf("midi_touch: ch %d, val %d\n", channel, value);
  673.     mpu_command(MC_SND_MIDI);
  674.     mpu_write(MIDI_TOUCH | MIDI_CHANNEL(channel));
  675.     mpu_write(MIDI_DATA(value));
  676. }
  677.  
  678. /****************************************************************************
  679. *                   mpu_command
  680. * Inputs:
  681. *    int c: Character to write to MPU-401 command port
  682. * Effect: 
  683. *    Writes the data to the MPU-401 command port
  684. ****************************************************************************/
  685.  
  686. private void mpu_command(c)
  687.     int c;
  688. {
  689.     if (!mpuflag) { /* simulated */
  690.     trace_mpu_command(c);
  691.     } else { /* real */
  692.     if (miditrace) trace_mpu_command(c);
  693.     mpu_drr_wait();
  694.     Ack = 0;
  695.     outp(COMPORT, c);
  696.     if (enabled) mpu_wait();
  697.     else wfa();
  698.     }
  699. }
  700.  
  701. /****************************************************************************
  702. *                 mpu_drr_wait
  703. * Effect: 
  704. *    Waits until the MPU-401 is ready to receive data
  705. ****************************************************************************/
  706.  
  707. #define MAX_TRIES    2000
  708.  
  709. private void mpu_drr_wait()
  710. {
  711.     int i;
  712.  
  713.     if (!mpuflag) return;    /* always ready if not there! */
  714.  
  715.     for (i = 0; i < MAX_TRIES; i++)
  716.     if ((inp(STATPORT) & DRR) == 0) break;
  717. #ifdef DEBUG
  718.     if (i == MAX_TRIES)
  719.     printf("mpu-401 not ready to receive; intcnt=%d\n",intcnt);
  720. #endif
  721. }
  722.  
  723. /****************************************************************************
  724. *                  mpu_error_check
  725. * Effect: 
  726. *    Reports any errors originating in the interrupt handler
  727. ****************************************************************************/
  728.  
  729. void mpu_error_check()
  730. {
  731.     if (Unknown != ACK) {
  732.     printf("Unknown command: %x\n", Unknown);
  733.     Unknown = ACK;
  734.     }
  735.     if (interror != 0) {
  736.     char *cause;
  737.     switch (interror) {
  738.         case NESTERR: cause = "nested interrupts";    break;
  739.         case BUFFERR: cause = "buffer overflow";    break;
  740.         case CMDERR:  cause = "unknown command";    break;
  741.         default: cause = "";           break;
  742.     }
  743.     printf("interror: %s\n", cause);
  744.     if (*cause == NULL) printf("%d\n", interror);
  745.  
  746.     interror = 0;
  747.     }
  748.     if (timeerr != 0) {
  749.     if (timeerr == TIMEOUT) printf("timeerr: timeout error\n");
  750.     else printf("timeerr = %d\n", timeerr);
  751.     timeerr = 0;
  752.     }
  753. }
  754.  
  755. /****************************************************************************
  756. *                   mpu_read
  757. * Result: int
  758. *    character read from MPU-401
  759. * Effect: 
  760. *    Reads the MPU-401
  761. ****************************************************************************/
  762.  
  763. private int mpu_read()
  764. {
  765.     int delay;
  766.     for (delay = 0; delay < 2000; delay++) {
  767.     if ((inp(STATPORT) & DSR) == 0)
  768.         return inp(DATAPORT);
  769.     }
  770. #ifdef DEBUG
  771.     printf("mpu_read: DSR never went low, returning 0, intcnt=%d\n",intcnt);
  772. #endif
  773.     return 0;
  774. }
  775.  
  776. /****************************************************************************
  777. *                   mpu_wait
  778. * Effect: 
  779. *    Called when interrupts are enabled.  Polls the 'Ack' flag, which is
  780. *    set by the interrupt handler.  If more than MAX_ACK_WAIT iterations
  781. *    occur without 'Ack' being set, issues an error message.
  782. *    Ack is cleared when it is detected.
  783. ****************************************************************************/
  784.  
  785. private void mpu_wait()
  786. {
  787.     int ackcnt; /* delay counter */
  788.  
  789.     if (!mpuflag) return;
  790.  
  791.     for (ackcnt = 0; ackcnt < MAX_ACK_WAIT; ackcnt++) {
  792.     if (Ack) {
  793.         if (max_ack_wait < ackcnt) max_ack_wait = ackcnt;
  794.         Ack = 0;
  795.         return;
  796.     }
  797.     }
  798. #ifdef DEBUG
  799.     printf("mpu_wait: No ack; incnt = %d\n",intcnt);
  800. #endif
  801. }
  802.  
  803. /****************************************************************************
  804. *                   mpu_write
  805. * Inputs:
  806. *    int c: Character to write to MPU-401 data port
  807. * Effect: 
  808. *    Writes the data to the MPU-401 data port
  809. ****************************************************************************/
  810.  
  811. private void mpu_write(c)
  812.     int c;
  813. {
  814.     if (!mpuflag) { /* simulate */
  815.     printf("%02x",c);
  816.     len += 2;
  817.     } else { /* real */
  818.     if (miditrace) { /* trace */
  819.         printf("%02x",c);
  820.         len += 2;
  821.     } /* trace */
  822.     mpu_drr_wait();
  823.     outp(DATAPORT, c);
  824.     }
  825. }
  826.  
  827. /****************************************************************************
  828. *                mpuexists
  829. * Inputs:
  830. *    boolean flag: true or false
  831. * Effect:
  832. *    if argument is false, indicates no mpu is on the machine, so
  833. *    simulate mpu-401 (for debugging only)
  834. ****************************************************************************/
  835.  
  836. void mpuexists(flag)
  837.     boolean flag;
  838. {
  839.     mpuflag = flag;
  840. }
  841.  
  842. /*****************************************************************
  843. *            set_pitch_default
  844. *****************************************************************/
  845. private void set_pitch_default()
  846. {
  847.     int i;
  848.  
  849.     for (i = 0; i < 128; i++) {
  850.     pit_tab[i].pbend = 8192;
  851.     pit_tab[i].ppitch = i;
  852.     }
  853. }
  854.  
  855. /*****************************************************************
  856. *            read_tuning
  857. *****************************************************************/
  858. void read_tuning(filename)
  859.     char *filename;
  860. {
  861.     int index, pit, lineno = 0;
  862.     float bend;
  863.     FILE *fpp;
  864.  
  865.     user_scale = true;
  866.     set_pitch_default();
  867.     fpp = fileopen(filename, "tun", "r", "Tuning definition file");
  868.     while ((fscanf(fpp, "%d %d %f\n", &index, &pit, &bend) > 2) &&
  869.        (lineno < 128)) {
  870.     lineno++;
  871.     if (index >= -12 && index <= 115) {
  872.         pit_tab[index+12].pbend = (int)(8192 * bend/100 + 8192);
  873.         pit_tab[index+12].ppitch = pit;
  874.     }
  875.     }
  876. }
  877.  
  878. /****************************************************************************
  879. *                   musicinit
  880. * Effect: 
  881. * Initialize the mpu 401 device driver
  882. *    Initialize mpu 401
  883. *        Reset 401, change defaults
  884. *    Set up interrupts
  885. *    Start up mpu record clock
  886. ****************************************************************************/
  887.  
  888. void musicinit()
  889. {
  890.     int version, revision;
  891.     int i;
  892.     char *filename;
  893.  
  894.     if (!tune_flag) {    /* do this code only once */
  895.     miditrace = (cl_nswitch(m_switches, n_m_sw) != NULL);
  896.     musictrace = (cl_nswitch(t_switches, n_t_sw) != NULL);
  897.  
  898.         tune_flag = true;
  899.     filename = cl_option("-tune");
  900.     if (filename != NULL) {
  901.         read_tuning(filename);
  902.     }
  903.  
  904.     intr_init();
  905.     }
  906.  
  907.     last_cmd = 0;
  908.  
  909. #ifdef TIMDIF
  910.     if (!initialized) settime();
  911. #endif
  912.  
  913.     initialized = true;
  914.  
  915.     intr_disable(IRQ);        /* Turn off 401 interrupts */
  916.  
  917.     for (i = 0; i < 100; i++) { /* flush out buffer, ignore DSR */
  918.     inp(DATAPORT);
  919.     }
  920.  
  921.     mpu_command(MC_RESET);    /* Reset the device */
  922.  
  923.     mpu_command(MC_VERSION);
  924.     version = mpu_read();
  925.  
  926.     mpu_command(MC_REVISION);
  927.     revision = mpu_read();
  928.  
  929.     mpu_command(MC_SET_TEMPO);    /* Set tempo and timebase to get */
  930.     mpu_write(MD_BEATS_PER_MINUTE);    /* 400 ticks per second */
  931.  
  932.     mpu_command(MC_TIMEBASE_192);
  933.  
  934.     if (metroflag)
  935.     mpu_command(MC_ON_METRONOME);    /* Just for debugging */
  936.  
  937.     mpu_command(MC_NO_MEASURE_END);    /* Don't want measure end bytes */
  938.  
  939.     init_asm();            /* Do any asm init needed(aintr.asm)*/
  940.     intr_routine(IRQ);        /* Set up vector */ 
  941.  
  942.     CBREAK = false;
  943.     setctl();            /* Set up ctrl-break intercept */
  944.  
  945. #ifdef DEBUG
  946.     loop_max = 0;
  947. #endif
  948.     intr_enable(IRQ);        /* allow 401 interrupts */
  949.  
  950.     if (user_scale) {
  951.     for (i = 0; i < num_voices; i++) {
  952.         midi_bend(i, 8192);
  953.         bend[i] = 8192;
  954.     }
  955.     }
  956.     midi_thru(!(cl_switch("-block")));    /* set MIDI thru on MPU-401 */
  957.  
  958.     timereset();        /* Reset clock */
  959. }
  960.  
  961. /****************************************************************************
  962. *                   musicterm
  963. * Effect: 
  964. *    Cleans up; disables MPU-401 interrupts; resets MIDI devices
  965. ****************************************************************************/
  966.  
  967. void musicterm()
  968. {
  969.     if (initialized) {
  970. #ifdef TIMDIF
  971.     cletime();
  972. #endif
  973.     intr_disable(IRQ);    /* No more 401 interrupts */
  974. #ifdef DEBUG
  975.     printf("loop_max is %d\n", loop_max);
  976. #endif
  977.     clrctl();        /* reset ctrl-break handler */
  978.     intr_cleanup(IRQ);    /* Restore default vector */
  979.     mpu_command(MC_RESET);    /* Reset the device */
  980.     initialized = false;
  981.     }
  982. /*  printf("maximum successful wait for ack: %d\n", max_ack_wait);*/
  983. }
  984.  
  985. /****************************************************************************
  986. *                    random
  987. * Inputs:
  988. *    int lo: Lower limit of value
  989. *    int hi: Upper limit of value
  990. * Result: int
  991. *    random number (lo <= result <= hi)
  992. ****************************************************************************/
  993.  
  994. private long seed = 1534781;
  995.  
  996. int random(lo, hi)
  997.     int lo, hi;
  998. {
  999.     seed *= 13;
  1000.     seed += 1874351;
  1001.     return (int) (lo + 
  1002.         (((hi + 1 - lo) * ((0x00ffff00 & seed) >> 8)) >> 16));
  1003. }
  1004.  
  1005. /****************************************************************************
  1006. *                   timereset
  1007. * Effect: 
  1008. *    Resets the time on the MPU-401.     Ticks is reset to 0
  1009. ****************************************************************************/
  1010.  
  1011. void timereset()
  1012. {
  1013.     if (!initialized) fixup();
  1014.     if (musictrace) printf("timereset()\n");
  1015.     Ticks = 0;                /* Reset clock */
  1016.     mpu_command(MC_START_RECORDING);    /* Starts up clock */
  1017. #ifdef TIMDIF
  1018.     cletime();
  1019.     settime();
  1020. #endif    
  1021. }
  1022.  
  1023. /****************************************************************************
  1024. *                   trace
  1025. * Inputs:
  1026. *    boolean flag: true for trace on
  1027. * Effect: 
  1028. *    turns tracing on (flag == true) or off (flag == false)
  1029. ****************************************************************************/
  1030. void trace(flag)
  1031.     boolean flag;
  1032. {
  1033.     musictrace = flag;
  1034. }
  1035.  
  1036. /****************************************************************************
  1037. *                   tracemidi
  1038. * Inputs:
  1039. *    boolean flag: true for trace on
  1040. * Effect: 
  1041. *    turns midi tracing on (flag == true) or off (flag == false)
  1042. ****************************************************************************/
  1043. void tracemidi(flag)
  1044.     boolean flag;
  1045. {
  1046.     miditrace = flag;
  1047. }
  1048.  
  1049. /****************************************************************************
  1050. *                   trace_mpu_command
  1051. * Inputs:
  1052. *    int c: Command
  1053. * Effect: 
  1054. *    Writes command to stdout
  1055. ****************************************************************************/
  1056.  
  1057. private void trace_mpu_command(c)
  1058.     int c;
  1059. {
  1060.     char * p;
  1061.     char buf[10];
  1062.  
  1063.     switch(c) { /* decode */
  1064.     case MC_RESET:
  1065.         p = " RESET:";
  1066.         break;
  1067.     case MC_ON_METRONOME:
  1068.         p =" MET-ON:";
  1069.         break;
  1070.     case MC_SET_TEMPO:
  1071.         p =" TEMPO:";
  1072.         break;
  1073.     case MC_TIMEBASE_192:
  1074.         p =" TIME-192:";
  1075.         break;
  1076.     case MC_START_RECORDING:
  1077.         p =" REC-ON:";
  1078.         break;
  1079.     case MC_VERSION:
  1080.         p =" VERSION:";
  1081.         break;
  1082.     case MC_REVISION:
  1083.         p =" REVISION:";
  1084.         break;
  1085.     case MC_NO_MEASURE_END:
  1086.         p =" NO-MEAS-END:";
  1087.           break;
  1088.     case MC_SND_MIDI:
  1089.         p =" MIDI:";
  1090.         break;
  1091.     case MC_RECORD_COUNTER:
  1092.         if (last_cmd == c) p = "#";
  1093.         else p = " COUNTER:";
  1094.         break;
  1095.     case MC_ON_BEND:
  1096.         p = "Bender:On";
  1097.         break;
  1098.     case MC_OFF_BEND:
  1099.         p = "Bender:Off";
  1100.         break;
  1101.     case MC_ON_THRU:
  1102.         p = "Thru:On";
  1103.         break;
  1104.     case MC_OFF_THRU:
  1105.         p = "Thru:Off";
  1106.         break;
  1107.     default:sprintf(buf," %02x",c);
  1108.         p = buf;
  1109.         break;
  1110.     } /* decode */
  1111.  
  1112.     last_cmd = c;
  1113.  
  1114.     if (len + strlen(p) > 70) { /* overflow */
  1115.     printf("\n");
  1116.     len = 0;
  1117.     } /* overflow */
  1118.     len += strlen(p);
  1119.     printf("%s",p);
  1120. }
  1121.  
  1122. /****************************************************************************
  1123. *                      wfa
  1124. * Effect: 
  1125. *    Waits for an acknowledgement from the MPU-401.    Will not wait more
  1126. *    than MAX_ACK_WAIT iterations thru its loop.
  1127. * Conditions:
  1128. *    Called only if interrupts are not enabled, and the MPU-401 is
  1129. *    being polled
  1130. ****************************************************************************/
  1131.  
  1132.  
  1133. private void wfa()
  1134. {
  1135.     int ackcnt;
  1136.     int x;
  1137.    
  1138.     if (!mpuflag) return;
  1139.  
  1140.     for (ackcnt = 0; ackcnt < MAX_ACK_WAIT; ackcnt++)
  1141.     if ((x = mpu_read()) == ACK) break;
  1142. #ifdef DEBUG
  1143.     else printf("wfa: got %x; intcnt = %d\n", x, intcnt);
  1144. #endif
  1145. }
  1146.  
  1147.